package com.harry.resource.workflow.module.mgr;

import java.util.Map;
import java.util.stream.Stream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import com.harry.basis.BasePoEntity;
import com.harry.decoupling.impl.module.RestfulMgrImpl;
import com.harry.resource.inner.entity.InnerUser;
import com.harry.resource.workflow.entity.WorkActivityDefinition;
import com.harry.resource.workflow.entity.WorkActivityInstance;
import com.harry.resource.workflow.entity.WorkFlowInstance;
import com.harry.resource.workflow.entity.WorkRoute;
import com.harry.resource.workflow.entity.WorkStateInstance;
import com.harry.utility.InnerUtils;
import com.harry.utility.PoEntityHelper;
import com.harry.utility.WorkFlowHelper;
import com.harry.utility.query.InnerCriteria;

public class WorkActivityInstanceRestfulMgr extends RestfulMgrImpl<WorkActivityInstance> {

	@Override
	public void post(Map<String, Object> params, HttpServletRequest request, HttpServletResponse response, Map<String, Object> data) throws Exception {
		// 1. prepare sources
		WorkStateInstance stateInstance = srv().one(WorkStateInstance.class, (String) PoEntityHelper.readValueByProperty(params, "stateInstance.id"));
		WorkActivityDefinition activityDefinition = srv().one(WorkActivityDefinition.class, (String) PoEntityHelper.readValueByProperty(params, "activityDefinition.id"));
		WorkFlowInstance flowInstance = (WorkFlowInstance) PoEntityHelper.readValueByProperty(stateInstance, "flowInstance");
		// 2. filling default
		PoEntityHelper.writeValueByProperty(params, "users", findUsersByUserCondition(flowInstance, activityDefinition));
		PoEntityHelper.writeValueByProperty(params, "activityPropInstances", createActivityPropInstances(params, flowInstance, activityDefinition));
		super.post(params, request, response, data);
	}

	@Override
	public void patch(Map<String, Object> params, HttpServletRequest request, HttpServletResponse response, Map<String, Object> data) throws Exception {
		super.patch(params, request, response, data);
		WorkFlowInstance flowInstance = (WorkFlowInstance) PoEntityHelper.readValueByProperty(data.get("data"), "stateInstance.flowInstance");
		Object[] routes = (Object[]) PoEntityHelper.readValueByProperty(data.get("data"), "stateInstance.stateDefinition.sourceRoutes");
		for (int i = 0; i < routes.length; i++) {
			WorkRoute route = (WorkRoute) routes[i];
			if (WorkFlowHelper.doesRouteMatch(flowInstance, route)) {
				InnerUtils.mgrSave(WorkStateInstance.class, InnerUtils.mapObject("flowInstance", InnerUtils.idObj(flowInstance), "stateDefinition", InnerUtils.idObj(route.getTargetStateDefinition())));
				break;
			}
		}
	}

	@SuppressWarnings("unchecked")
	private Object[] findUsersByUserCondition(WorkFlowInstance flowInstance, WorkActivityDefinition activityDefinition) throws Exception {
		// 1. prepare property
		Class<? extends BasePoEntity> rootEntityType;
		String rootEntityId;
		String userProperty;
		InnerCriteria criteria;
		if (StringUtils.isEmpty(activityDefinition.getUsersProperty())) {
			userProperty = "id";
			rootEntityType = InnerUser.class;
			rootEntityId = null;
			criteria = de().parse(PoEntityHelper.readValueByProperty(activityDefinition, "usersCriteria"), InnerCriteria.class);
		} else {
			// 1. prepare propertyPath, contextMap
			String propertyPath = PoEntityHelper.appendIfAbsent(activityDefinition.getUsersProperty(), ".id");
			Map<String, Object> contextMap = WorkFlowHelper.findRealVariableMap(WorkFlowHelper.findWorkVariableMap(flowInstance));
			String[] properties = PoEntityHelper.splitProperties(propertyPath);
			// 2. assign arguments for querying userIds
			userProperty = Stream.of(properties).skip(1l).reduce("", (p, n) -> p + "." + n).substring(1);
			rootEntityType = (Class<? extends BasePoEntity>) PoEntityHelper.readValueByProperty(contextMap, properties[0]).getClass();
			rootEntityId = (String) PoEntityHelper.readValueByProperty(contextMap, properties[0] + ".id");
			criteria = de().parse(PoEntityHelper.parseJSEL(contextMap, (String) PoEntityHelper.readValueByProperty(activityDefinition, "usersCriteria")), InnerCriteria.class);
		}
		return Stream.of(PoEntityHelper.loadProperty(rootEntityType, rootEntityId, userProperty, criteria)).map(id -> InnerUtils.idObj(id)).toArray();
	}

	private Object[] createActivityPropInstances(Map<String, Object> params, WorkFlowInstance flowInstance, WorkActivityDefinition activityDefinition) throws Exception {
		String[] activityPropDefinitionIds = PoEntityHelper.loadProperty(WorkActivityDefinition.class, activityDefinition.getId(), "activityPropDefinitions.id", new InnerCriteria());
		Object[] objects = new Object[activityPropDefinitionIds.length];
		for (int i = 0; i < activityPropDefinitionIds.length; i++) {
			objects[i] = InnerUtils.mapObject(// e
					"activityInstance", params, // e
					"activityPropDefinition", InnerUtils.idObj(activityPropDefinitionIds[i])// e
			);
		}
		return objects;
	}
}
